package com.common.commonlibrary.utils

import android.content.Context
import android.graphics.*
import android.media.MediaPlayer
import android.text.TextUtils
import android.util.Log
import com.orhanobut.logger.Logger
import java.io.*


/**
 *@project ScanningPen
 *@auther chenzhuang
 *@date 2020/4/26 9:53
 *@describe
 */
object FileUtils {

    //  文本摘抄
    val PATH_EXCERPT: String =
        android.os.Environment.getExternalStorageDirectory().absolutePath + "/excerpt"

    //  文本扫译原文、译文的音频文件
    val PATH_TEXT_AUDIO: String =
        android.os.Environment.getExternalStorageDirectory().absolutePath + "/textaudio"

    //  相册
    val PATH_PICTURE: String =
        android.os.Environment.getExternalStorageDirectory().absolutePath + "/picture"

    //  智能录音
    val PATH_RECORDER: String =
        android.os.Environment.getExternalStorageDirectory().absolutePath + "/record"

    //  智能录音--dosmono298音频
    val PATH_RECORDER_VEDIO: String =
        android.os.Environment.getExternalStorageDirectory().absolutePath + "/record"

    //  智能录音--dosmono298文字
    val PATH_RECORDER_TEXT: String =
        android.os.Environment.getExternalStorageDirectory().absolutePath + "/record"

    //  语音翻译
    val PATH_VOICE_TRANSLATION: String =
        android.os.Environment.getExternalStorageDirectory().absolutePath + "/VoiceTrans"

    //  拍题搜题
    val PATH_TOPIC: String =
        android.os.Environment.getExternalStorageDirectory().absolutePath + "/topic"

    val TOPIC_JSON: String =
        android.os.Environment.getExternalStorageDirectory().absolutePath + "/topicjson"

    // 离线资源拷贝源目录
    const val PATH_LOCAL_RES_SOURCE: String = "/system/etc/sdcard/dosmono"
    //const val PATH_LOCAL_RES_SOURCE: String = "/sdcard"//jinshang3.46

    // 离线资源拷贝目标目录
    const val PATH_LOCAL_RES_TARGET: String = "/sdcard/dosmono"

    /**
     * 生成文件
     *
     * @param dir
     * @param name
     * @return
     */
    fun createFile(dir: String, name: String): String? {
        val dirFile = File(dir)
        if (!dirFile.exists()) {
            dirFile.mkdirs()
        }
        val file = File(dir, name)
        try {
            if (!file.exists()) {
                file.createNewFile()
            }
            return file.absolutePath
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return null
    }


    /**
     * 创建文件
     *
     * @return
     */
    fun createFile(file: File): Boolean {
        var r = false
        if (!file.exists()) {
            try {
                if (file.parentFile != null
                    && !file.parentFile.exists()
                ) {
                    r = file.parentFile.mkdirs()
                }
                r = file.createNewFile()
            } catch (e: IOException) {
            }
        }
        return r
    }

    /**
     * 获取文件名称
     */
    fun getFileName(suffix: String): String {
        return "" + System.currentTimeMillis() + ((Math.random() * 9.0 + 1.0) * 1000.0).toInt() + "." + suffix
    }

    /**
     * 修改文件后缀
     *
     * @param oldPath
     * @param suffix
     */
    fun renameSuffix(oldPath: String, suffix: String): String {
        val newPath = oldPath.substring(0, oldPath.lastIndexOf(".") + 1) + suffix
        return if (renameFile(oldPath, newPath)) {
            newPath
        } else {
            oldPath
        }
    }

    /**
     * 重命名文件
     *
     * @param oldPath 原来的文件地址
     * @param newPath 新的文件地址
     */
    fun renameFile(oldPath: String, newPath: String): Boolean {
        val oleFile = File(oldPath)
        val newFile = File(newPath)
        //执行重命名
        return oleFile.renameTo(newFile)
    }

    /**
     * 删除文件夹
     *
     * @param dir
     * @param delSelf
     * @return
     */
    fun deleteDir(path: String, delSelf: Boolean): Boolean {
        var dir = path
        if (!dir.endsWith(File.separator)) { // 如果dir不以文件分隔符结尾，自动添加文件分隔符
            dir += File.separator
        }
        val dirFile = File(dir)
        Logger.d("deleteDir dirFile:${if (dirFile.exists()) dirFile.isDirectory else null}, dir:$dir")
        if (!dirFile.exists() || !dirFile.isDirectory) { // 如果dir对应的文件不存在，或者不是一个目录，则退出
            return false
        }
        var flag = true
        val files = dirFile.listFiles()
        if (files.isNullOrEmpty()) {
            return if (delSelf) {
                dirFile.delete()
            } else {
                true
            }
        }
        for (i in files.indices) { // 删除子文件
            if (files[i].isFile) {
                flag = deleteFile(files[i].absolutePath)
                if (!flag) {
                    break
                }
            } else { // 删除子目录
                flag = deleteDirectory(files[i].absolutePath)
                if (!flag) {
                    break
                }
            }
        }
        if (!flag) {
            return false
        }
        return if (delSelf) {
            dirFile.delete()
        } else {
            true
        }
    }

    /**
     * 删除文件目录下的所有文件
     *
     * */
    fun dirListFile(path: String): Boolean {
        val file = File(path)
        if (!file.exists() || !file.isDirectory) {
            Logger.i("dirListFile>>> false")
            return false
        }
        try {
            for (item in file.listFiles()) {
                if (item.isFile && (item.name.contains(".mp3") ||
                            item.name.contains(".pcm") ||
                            item.name.contains(".wav")
                            )
                ) {
                    item.delete() // 删除所有文件
                }
            }
            Logger.i("dirListFile>>> true")
            return true
        } catch (e: Exception) {
            Logger.i("dirListFile>>> false")
            return false
        }
    }

    /**
     * 删除目录（文件夹）以及目录下的文件
     *
     * @param dir 被删除目录的文件路径
     * @return 目录删除成功返回true, 否则返回false
     */
    fun deleteDirectory(dir: String): Boolean {
        var dir = dir
        if (!dir.endsWith(File.separator)) { // 如果dir不以文件分隔符结尾，自动添加文件分隔符
            dir += File.separator
        }
        val dirFile = File(dir)
        if (!dirFile.exists() || !dirFile.isDirectory) { // 如果dir对应的文件不存在，或者不是一个目录，则退出
            return false
        }
        var flag = true
        val files = dirFile.listFiles()
        if (files != null) {
            for (i in files.indices) { // 删除子文件
                if (files[i].isFile) {
                    flag = deleteFile(files[i].absolutePath)
                    if (!flag) {
                        break
                    }
                } else { // 删除子目录
                    flag = deleteDirectory(files[i].absolutePath)
                    if (!flag) {
                        break
                    }
                }
            }
        }
        if (!flag) {
            return false
        }
        return dirFile.delete()
    }

    /**
     * 删除单个文件
     *
     * @param pathName 被删除文件的文件名
     * @return 单个文件删除成功返回true, 否则返回false
     */
    fun deleteFile(pathName: String): Boolean {
        val file = File(pathName)
        return if (file.isFile && file.exists()) {
            file.delete()
            true
        } else {
            false
        }
    }

    /** 查询文件是否存在*/
    fun queryFileIsExist(path: String): Boolean {
        return try {
            val f = File(path)
            Logger.i("queryFileIsExist>>> 播放文件 = ${f.exists()}")
            f.exists()
        } catch (e: Exception) {
            Logger.i("queryFileIsExist>>> 播放文件不存在")
            false
        }
    }

    /**
     * 保存到路径
     */
    fun saveFile(bm: Bitmap, path: String): String? {
        try {
            val f = File(path)
            val out = FileOutputStream(f)
            bm.compress(Bitmap.CompressFormat.JPEG, 100, out)
            out.flush()
            out.close()
            return path
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * bitmap压缩后转jpg
     */
    fun bmp2Jpg(bmp: Bitmap, path: String): Boolean {
        try {
            val targetWidth = 960
            if (bmp.width <= targetWidth) {
                return saveFile(bmp, path) != null
            }
            Logger.i("bmp2jpg to bytes start")
            val bos = ByteArrayOutputStream()
            bmp.compress(Bitmap.CompressFormat.JPEG, 100, bos)
            val bytes = bos.toByteArray()
            val options = BitmapFactory.Options()
            options.inJustDecodeBounds = true
            BitmapFactory.decodeByteArray(bytes, 0, bytes.size, options)
            Logger.i("bmp2jpg to bytes end")
            var be = 1
            if (options.outWidth > targetWidth) {
                be = options.outWidth / targetWidth
                be += if (options.outWidth % targetWidth > 0) 1 else 0
            }
            options.inSampleSize = be
            options.inJustDecodeBounds = false
            val source = BitmapFactory.decodeByteArray(bytes, 0, bytes.size, options)
            val fos = FileOutputStream(path)
            source.compress(Bitmap.CompressFormat.JPEG, 100, fos)
            fos.flush()
            fos.close()
            Logger.i("bmp2jpg to compress end")
            return true
        } catch (e: java.lang.Exception) {
            Logger.e("Scanning saveBitmap error:$e")
        }
        return false
    }

    /**
     * 图片线性灰度 十几ms
     */
    fun lineGrey(image: Bitmap): Bitmap? {
        Logger.d("bitmap 线性灰度 start")
        //得到图像的宽度和长度
        val width = image.width
        val height = image.height
        //创建线性拉升灰度图像
        var linegray: Bitmap? = null
        linegray = image.copy(Bitmap.Config.ARGB_8888, true)
        //依次循环对图像的像素进行处理
        for (i in 0 until width) {
            for (j in 0 until height) {
                //得到每点的像素值
                val col = image.getPixel(i, j)
                val alpha = col and -0x1000000
                var red = col and 0x00FF0000 shr 16
                var green = col and 0x0000FF00 shr 8
                var blue = col and 0x000000FF
                // 增加了图像的亮度
                red = (1.1 * red + 30).toInt()
                green = (1.1 * green + 30).toInt()
                blue = (1.1 * blue + 30).toInt()
                //对图像像素越界进行处理
                if (red >= 255) {
                    red = 255
                }
                if (green >= 255) {
                    green = 255
                }
                if (blue >= 255) {
                    blue = 255
                }
                // 新的ARGB
                val newColor = alpha or (red shl 16) or (green shl 8) or blue
                //设置新图像的RGB值
                linegray.setPixel(i, j, newColor)
            }
        }
        Logger.d("bitmap 线性灰度 end")
        return linegray
    }

    /**
     * 图片灰度 5、6ms
     */
    fun bitmap2Gray(bmSrc: Bitmap): Bitmap? {
        Logger.d("bitmap 灰度 start")
        // 得到图片的长和宽
        val width = bmSrc.width
        val height = bmSrc.height
        // 创建目标灰度图像
        var bmpGray: Bitmap? = null
        bmpGray = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
        // 创建画布
        val c = Canvas(bmpGray)
        val paint = Paint()
        val cm = ColorMatrix()
        cm.setSaturation(0f)
        val f = ColorMatrixColorFilter(cm)
        paint.colorFilter = f
        c.drawBitmap(bmSrc, 0f, 0f, paint)
        Logger.d("bitmap 灰度 end")
        return bmpGray
    }

    /**
     * 图片二值化 100多ms
     */
    fun gray2Binary(graymap: Bitmap): Bitmap? {
        //得到图形的宽度和长度
        Logger.d("bitmap 二值化 start")
        val width = graymap.width
        val height = graymap.height
        //创建二值化图像
        var binarymap: Bitmap? = null
        binarymap = graymap.copy(Bitmap.Config.ARGB_8888, true)
        //依次循环，对图像的像素进行处理
        for (i in 0 until width) {
            for (j in 0 until height) {
                //得到当前像素的值
                val col = binarymap.getPixel(i, j)
                //得到alpha通道的值
                val alpha = col and -0x1000000
                //得到图像的像素RGB的值
                val red = col and 0x00FF0000 shr 16
                val green = col and 0x0000FF00 shr 8
                val blue = col and 0x000000FF
                // 用公式X = 0.3×R+0.59×G+0.11×B计算出X代替原来的RGB
                var gray =
                    (red.toFloat() * 0.3 + green.toFloat() * 0.59 + blue.toFloat() * 0.11).toInt()
                //对图像进行二值化处理
                gray = if (gray <= 95) {
                    0
                } else {
                    255
                }
                // 新的ARGB
                val newColor = alpha or (gray shl 16) or (gray shl 8) or gray
                //设置新图像的当前像素值
                binarymap.setPixel(i, j, newColor)
            }
        }
        Logger.d("bitmap 二值化 end")
        return binarymap
    }


    /**
     * 文件复制
     *
     * @param src 原文件
     * @param dst 目标文件
     * @throws IOException
     */
    fun copy(src: File?, dst: File): Boolean {
        var result = false
        if (!dst.exists()) createFile(dst)
        var fis: InputStream? = null
        var out: OutputStream? = null
        try {
            fis = FileInputStream(src)
            out = FileOutputStream(dst)
            val buf = ByteArray(1024)
            var len: Int
            while (fis.read(buf).also { len = it } > 0) {
                out.write(buf, 0, len)
            }
            out.flush()
            result = true
        } catch (e: Exception) {
            Logger.e("copy error:$e")
        } finally {
            try {
                fis?.close()
                fis = null
                out?.close()
                out = null
            } catch (e: Exception) {
                Logger.e("copy close error:$e")
            }
        }
        return result
    }

    fun moveDir(src: String, dest: String): Boolean {
        val srcFile = File(src)
        if (!srcFile.exists()) {
            Logger.e("move dir src is null: $src")
            return false
        }
        var destFile = File(dest)
        Logger.d("moveDir src:$src is Dir:${srcFile.isDirectory}, dest:$dest is exit:${destFile.exists()}")
        if (srcFile.isDirectory) {
            if (destFile.exists() && !destFile.isDirectory) {
                Logger.e("move dir dest is not dir: $dest")
                return false
            }
            if (!destFile.exists()) {
                destFile.mkdir()
            } else {
                // 清空目标文件夹
                deleteDir(dest, false)
            }
            val list = srcFile.listFiles()
            if (!list.isNullOrEmpty()) {
                for (child in list) {
                    if (child.isFile) {
                        moveDir(child.absolutePath, dest)
                    } else if (child.isDirectory) {
                        moveDir(child.absolutePath, "$dest/${child.name}")
                    }
                }
                deleteDir(src, true)
            }
        } else if (srcFile.isFile) {
            if (destFile.isFile && destFile.exists()) {
                destFile.delete()
            }
            if (destFile.isDirectory) {
                destFile = File(destFile, srcFile.name)
            }
            srcFile.renameTo(destFile)
        }
        return true
    }


    /**
     * 获取音频文件的总时长大小
     *
     * @param filePath 音频文件路径
     * @return 返回时长大小
     */
    fun getAudioFileVoiceTime(filePath: String?): Long {
        var mediaPlayerDuration = 0L
        if (filePath == null || filePath.isEmpty()) {
            return 0
        }
        val mediaPlayer = MediaPlayer()
        try {
            mediaPlayer.setDataSource(filePath)
            mediaPlayer.prepare()
            mediaPlayerDuration = mediaPlayer.duration.toLong()
        } catch (ioException: IOException) {
            Logger.e("getAudioFileVoiceTime", ioException.message)
        }
        if (mediaPlayer != null) {
            mediaPlayer.stop()
            mediaPlayer.reset()
            mediaPlayer.release()
        }
        return mediaPlayerDuration
    }

    fun readFileContent(path: String, callback: OnFileIOCallback) {
        var content: String = ""
        val f = File(path)
        if (!f.exists() || !f.isFile) {
            callback.onError("file is not exists")
        }
        var fis: FileInputStream? = null
        try {
            fis = FileInputStream(f)
            val reader = BufferedReader(InputStreamReader(fis, "UTF-8"))
            while (true) {
                val buff: String? = reader.readLine()
                if (buff != null) {
                    content += buff
                } else {
                    break
                }
            }
            callback.onSuccess(content)
        } catch (e: java.lang.Exception) {
            Logger.e("read excerpt file content error:$e , path:$path")
            callback.onError("read excerpt file content error:$e , path:$path\"")
        } finally {
            try {
                fis?.close()
            } catch (e: java.lang.Exception) {
                callback.onError("read excerpt file content error:$e , path:$path\"")
            }
        }
    }

    fun writeFileContent(content: String, callback: OnFileIOCallback) {
        var path: String? = null
        val dirFirstFolder = File(TOPIC_JSON)//通过变量文件来获取需要创建的文件夹名字
        if (!dirFirstFolder.exists()) { //如果该文件夹不存在，则进行创建
            dirFirstFolder.mkdirs()//创建文件夹
        }

        try {
            path = getFileName("txt")
            val writeName = File(TOPIC_JSON + "/" + path) // 相对路径，如果没有则要建立一个新的output.txt文件
            writeName.createNewFile() // 创建新文件,有同名的文件的话直接覆盖
            try {
                val writer = FileWriter(writeName)
                val out = BufferedWriter(writer)
                out.write(content) // \r\n即为换行
                out.flush() // 把缓存区内容压入文件
                callback.onSuccess(path)
                out.close()
            } catch (e: IOException) {
                e.printStackTrace()
                e.message?.let { callback.onError(it) }
            }
        } catch (e: Exception) {
            e.message?.let { callback.onError(it) }
        }
    }

    /**
     * 判断文件夹是否存在
     */
    fun createFileToSave(path: String) {
        if (TextUtils.isEmpty(path)) return
        val file = File(path)
        if (!file.exists()) {
            file.mkdir()
        } else {
            Log.d("tag", "filePath 文件夹已经存在！！")
        }
    }

    /**
     * 检查字体文件是否存在
     */
    fun checkFontFileExist(context: Context, word: String): Boolean {
        return try {
            context.assets.open("strokes/font/$word.js")
            true
        } catch (e: Exception) {
            false
        }
    }

    interface OnFileIOCallback {
        fun onSuccess(value: String)
        fun onError(message: String)
    }
}